import json
import os
import threading
import time

#----------------------------------------------------
# install request :
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests
#----------------------------------------------------
import requests
import serial
class TZnIot:
    def __init__(self):
        self.config={}
        self.terInfo ={}
        self.devs ={}
        self.channels ={}

    def load(self , configFn):
        res = 0
        try:
            if os.path.exists(configFn):
                with open(configFn,'r') as f :
                    try:
                        configJson = f.read()
                        self.config = json.loads(configJson)
                        url = "/".join([self.config['infoUrl'],"db/ms/query"])
                        ps={
                            "dbKey_":"iotv10",
                            "dbPath_":"iot10/terminal/terminal",
                            "terCode": self.config['terminalCode']
                        }
                        resp = requests.post(url= url , data=ps)
                        dataJson = resp.text
                        datas = (json.loads(dataJson))['result']

                        terInfo = datas[0][0]
                        chs = datas[1]
                        devs = datas[2]
                        tasks = datas[3]
                        dps = datas[4]

                        self.terInfo = terInfo
                        for devInfo in devs:
                            dev = TDev()
                            dev.info = devInfo
                            try:
                                dev.info['exData'] = json.loads(devInfo['exInfo'])
                            except Exception as eer:
                                pass
                            self.devs[devInfo['devId']] = dev

                        for chInfo in chs:
                            ch = TChannel()
                            ch.info = chInfo
                            self.channels[ch.info['chId']] = ch

                        for taskInfo in tasks:
                            task = TTask()
                            task.info = taskInfo
                            taskId = taskInfo['taskId']
                            devId = taskInfo['devId']
                            chId = taskInfo['channelId']
                            self.channels[chId].tasks[taskId] = task
                            task.dev = self.devs[devId]
                            task.channel = self.channels[chId]
                            if not devId in  task.channel.devs.keys():
                                task.channel.devs[devId] = dev

                        for dpInfo in dps:
                            dp = TDp()
                            dp.info = dpInfo
                            dpId = dpInfo['dpKey']
                            devId = dpInfo['devId']
                            chId = dpInfo['chId']
                            taskId = dpInfo['taskId']
                            self.devs[devId].dps[dpId] = dp
                            self.channels[chId].tasks[taskId].dps[dpId] = dp
                        print('load sys objects...')
                    except Exception as err:
                        res = -1
                        print(err)
        except Exception as er:
            print(er)
        return  res
    def open(self):
        try:
            for ch in self.channels.values():
                ch.asyncStart()
        except Exception as er:
            print(er)
class TChannel:
    def __init__(self):
        self.info = {}
        self.devs ={}
        self.tasks = {}
        self.chThread = None

        self.serial = None
    def openChanel(self):
        res = 0
        try:
            chProtocol = self.info['protocol']
            if chProtocol == 'ICE645' or chProtocol=='ICE101' :
                res = self.openChanel_serial()
        except Exception as er:
            print(er)
        return  res
    def openChanel_serial(self):
        res = 0
        try:
            comPort = self.info['comPort']
            baudrate = self.info['comBaudrate']
            parity = self.info['comParity']
            self.serial = serial.Serial(comPort, baudrate , parity=parity, timeout=2)
            res = 1
        except Exception as er:
            res = -1
            print('open serial:'+ comPort+' fail.')
            print(er)
        return  res
    def start(self):
        try:
            openFlag = self.openChanel()
            if openFlag > 0 :
                while openFlag:
                    try:
                        time.sleep(0.01)
                        for task in self.tasks.values():
                            tmNow = time.time()
                            timeout = tmNow - task.lastRunTime > task.info['collectionCycle']
                            if timeout :
                                task.collection()
                        self.postChangeDps()
                    except Exception as err:
                        print(err)
        except Exception as er:
            print(er)
    def asyncStart(self):
        try:
            self.chThread = threading.Thread( target= self.start, daemon=True)
            self.chThread.start()
        except Exception as er:
            print(er)
    def postChangeDps(self):
        try:
            pass
        except Exception as er:
            print(er)
class TDev :
    def __init__(self):
        self.info = {}
        self.dps = {}
class TDp:
    def __init__(self):
        self.info = {}
class TTask :
    def __init__(self):
        self.info ={}
        self.dev = TDev()
        self.channel = TChannel()
        self.dps={}
        self.lastRunTime = 0
    def collection(self):
        try:
            chProtocol = self.channel.info['protocol']
            if chProtocol == 'ICE645' :
                self.collection_645()
        except Exception as er:
            print(er)
    def collection_645(self):
        try:
            for dp in self.dps.values():
                cmdBytes = None
                if 'cmdBytes' in dp.info.keys():
                    cmdBytes= dp.info['cmdBytes']
                else:
                    cmdBytes =[]
                    devAddr = self.dev.info['exData']['devAddr']
                    cmdBytes.append(0x68)
                    addrBytes = bytes(reversed( bytes.fromhex(devAddr)))
                    for i in range(len(addrBytes)):
                        cmdBytes.append(addrBytes[i])
                    cmdBytes.append(0x68)
                    cmdBytes.append(0x11)
                    cmdBytes.append(0x4)
                    dpAddr = '0000'+str(dp.info['regAddrStart'])
                    for i in [-1,-2,-3,-4]:
                        d = int(dpAddr[i]) + 0x33
                        cmdBytes.append(d)
                    cs = 0
                    for i in range(len(cmdBytes)):
                        cs = cs + cmdBytes[i]
                        cs = cs % 256
                    cmdBytes.append(cs)
                    cmdBytes.append(0x16)
                    dp.info['cmdBytes'] = cmdBytes
                self.channel.serial.write(cmdBytes)
                self.channel.serial.flush()

                rs68H1 = self.channel.serial.read(1)
                if len(rs68H1)>0 and rs68H1[0]==0x68:
                    rsHead = self.channel.serial.read(9)
                    if len(rsHead)==9 and rsHead[-3]==0x68:
                        bodySize = rsHead[-3]
                        recSize = bodySize + 2
                        rsBody = self.channel.serial.read(recSize)
                        print(rsBody)


                time.sleep(0.03)

        except Exception as er:
            print(er)
znIot = TZnIot()
configFn = "zniotConfig.txt"
znIot.load(configFn)
znIot.open()
while 1>0 :
    time.sleep(1)